import * as React from "react";
import * as THREE from "three";
import * as commonfunc from "../mixins/viewCommonFun";
import {
  ColorEnum,
  DrawEnum,
  SelectModeEnum,
  WIREFRAME,
  PlaneModeEnum,
  RenderOrderEnum,
  BJ_POINT_GROUP,
  YS_LINE_GROUP,
  waterCoolingResultKeyMap,
} from "../constants";
import { Line2 } from "three/examples/jsm/lines/Line2.js";
import { initAxes } from "../mixins/viewAxes";
import {
  addEventHandler,
  sleep,
  toExponential,
  isArray,
  isEmpty,
  isString,
  removeEventHandler,
  pick,
} from "../utils/utils";
import { LineGeometry } from "three/examples/jsm/lines/LineGeometry.js";
import {
  baseDecode,
  floatDecode,
  StatisticsUtils,
  getMaxVal,
  preventDefaults,
  throttle,
  toHexColor,
  getMinVal,
  getWireframeByFace,
  getLineMaterial,
} from "../components/core/ViewUtils";
import { LineMaterial } from "three/examples/jsm/lines/LineMaterial";
import { LineSegments2 } from "three/examples/jsm/lines/LineSegments2";
import { LineSegmentsGeometry } from "three/examples/jsm/lines/LineSegmentsGeometry";
import EventBus from "../utils/eventBus";
import CanvasRulerContainer from "../components/core/CanvasRulerContainer";
import "./style.css";
import { common } from "@mui/material/colors";
// 此类属性不能放vue data 里，
// 不然严重影响性能问题，卡顿掉帧严重
let animationId;
let raycasterObjs: THREE.Mesh[] = []; // 鼠标悬停/点击高亮显示的 obj 列表
const mitt = new EventBus();
let selectionBox, helper, boxAllSelected;
let delCallback,
  enterCallback,
  escCallback,
  ctrlSCallback,
  ctrlCallback,
  ctrlZCallback,
  dragCallback,
  ctrlCCallback,
  ctrlVCallback,
  shiftCallback;

type CounterState = {
  value: number;
  representation: number;
  coneResolution: number;
  originalAspect: number;
  curControl: any;
  curCamera: any;
  rulerLoaded: boolean;
  collapsed: boolean;
  distanceLong: number;
  modelLong: number;
  rightMenuVisible: boolean;
  isMoved: boolean;
  selectColor: THREE.ColorRepresentation;
  defaultColor: THREE.ColorRepresentation;
  curActiveObj: any;
  selectMode: string;
  // fullScreenRenderer: vtkFullScreenRenderWindow;
  centerPoint: {
    object:
      | { visible: boolean }
      | null
      | THREE.Mesh<THREE.SphereGeometry, THREE.MeshBasicMaterial>
      | undefined;
    xyz: any;
    normal: any;
  };
};
type CounterProps = { taskInfoLoading: boolean };
const camCenter = new THREE.Vector3(0, 0, 0);
const viewSize = 409;
let rebackList: Function[] = [];
class ShoeView extends React.Component<CounterProps, CounterState> {
  canvasRulerRef = React.createRef();
  pointer = { x: 0, y: 0 };
  clientX = 0;
  clientY = 0;
  curPrePlaneMode: string | null = "";
  curPlaneMode = "";
  gridHelper: THREE.Group | THREE.GridHelper | null;
  diyPoint: THREE.Vector3;
  curDraw: any;
  sphereCount: number;
  nickname: string;
  originVisible: boolean;
  isInitDrawCurve: boolean;
  curvesMap: any[];
  drawing: boolean;
  currentActiveItem: any;
  mirrorCurve: any;
  currentFunc: Function;
  inited: boolean;
  throttleMouseMoveHandler: any;
  pointCount: number;
  intersectObjects: any[];
  circleSetting: any;
  curveCount: number;
  tempCurvesGroup: any;
  modalEdit: boolean;
  controlling: boolean;
  translate: {
    points: THREE.Vector3[];
    showSetting: boolean;
    closeFunc?: Function;
    tempObj?: THREE.Object3D;
    currentItem: null;
    curve?: {
      nickname: string;
    };
  };
  helixSetting: {
    _point: THREE.Vector3 | null;
    drawEnd: boolean;
    showSetting: boolean;
    turnsNum: number;
    radius: number;
    point: THREE.Vector3 | null | THREE.Mesh;
    newPoint: THREE.Vector3 | null;
    drawResult: null;
  };
  direction: string;

  //******私有变量 */
  state: CounterState = {
    value: 0,
    representation: 2,
    coneResolution: 6,
    originalAspect: 0,
    curControl: null,
    curCamera: null,
    rulerLoaded: false,
    collapsed: false,
    distanceLong: 0,
    modelLong: 0,
    rightMenuVisible: false,
    isMoved: false,
    selectColor: ColorEnum.origin,
    defaultColor: ColorEnum.origin,
    curActiveObj: undefined,
    selectMode: "",
    centerPoint: {
      object: null,
      xyz: null,
      normal: null,
    },

    // fullScreenRenderer: vtkFullScreenRenderWindow.newInstance(),
    // thisPointRenderer:null,
  };

  componentDidMount() {
    this.initView();
    //	  commonfunc.createControl
    this.setState({
      curControl: {
        cache: false,
        get() {
          return commonfunc.getCurrControl();
        },
      },
    });
  }
  componentDidUpdate(
    prevProps: Readonly<CounterProps>,
    prevState: Readonly<CounterState>,
    snapshot?: any
  ): void {}
  shouldComponentUpdate(
    nextProps: Readonly<CounterProps>,
    nextState: Readonly<CounterState>,
    nextContext: any
  ): boolean {
    // if(this.state.curControl!== nextState.curControl){
    //     return true
    // }
    return false;
  }
  static getDerivedStateFromProps(props, state) {
    // if(state.curControl)
    return null;
  }
  updateColor = (list, hexColor, lineColor: number = 0) => {
    for (const item of list) {
      if (this.state.curActiveObj) {
        if (
          this.state.selectMode !== SelectModeEnum.line &&
          this.state.selectMode !== SelectModeEnum.point &&
          this.isModelFace(item)
        ) {
          item.material?.color.set(new THREE.Color(hexColor));
          item.material?.emissive.set(new THREE.Color(0x333333));
        }
        if (
          this.state.selectMode === SelectModeEnum.line &&
          this.isModelEdge(item)
        ) {
          item.material?.color.set(new THREE.Color(lineColor ?? hexColor));
        }
      } else {
        if (this.isModelFace(item)) {
          item.material?.color.set(new THREE.Color(hexColor));
          item.material?.emissive.set(new THREE.Color(0x333333));
        }
        if (this.isModelEdge(item)) {
          item.material?.color.set(new THREE.Color(lineColor ?? hexColor));
        }
      }
      item.material.needsUpdate = true;
    }

    return list;
  };
  /**
   * 设置鼠标点击点坐标
   */
  setPoint(event, point) {
    const sliderWidth = 320;
    const headerHeight = 52;
    const canvas = commonfunc.getCanvas();
    const x =
      ((event.clientX - (this.state.collapsed ? 0 : sliderWidth)) /
        canvas.clientWidth) *
        2 -
      1;
    const y = -((event.clientY - headerHeight) / canvas.clientHeight) * 2 + 1;
    point.set(x, y, 0.5);
  }
  pointermoveFun = (event) => {
    if (helper && helper.isDown) {
      this.updateColor(
        selectionBox.collection,
        this.state.defaultColor,
        ColorEnum.black
      );
      this.setPoint(event, selectionBox.endPoint);
      const allSelected = selectionBox.select();
      this.updateColor(allSelected, this.state.selectColor);
      // logger.log('pointermoveFun allSelected: ', this.selectColor);
      this.requestRender();
    }
  };
  removePointerEvent() {
    this.setState({
      isMoved: false,
    });
    const domElement = document.querySelector("#mainCanvas");
    removeEventHandler(domElement, "pointermove", (event) =>
      this.pointermoveFun(event)
    );
    removeEventHandler(domElement, "pointerup", (event) =>
      this.pointermoveFun(event)
    );
  }
  /**
   * 模具的面或边
   */
  isModelFaceOrEdge(obj) {
    return this.isModelFace(obj) || this.isModelWireframe(obj);
  }

  /**
   * 模具的面
   */
  isModelFace(obj) {
    return obj.nickname?.startsWith("face_");
  }

  /**
   * 模具的边
   */
  isModelEdge(obj) {
    return (
      (obj.nickname?.startsWith("e_") && obj.allowSelect) ||
      obj.nickname?.startsWith("circle_")
    );
  }

  /**
   * 模具的线框
   */
  isModelWireframe(obj) {
    return obj.groupName === WIREFRAME || obj.isWireframe;
  }

  /**
   * 变径点
   */
  isBjPoint(obj) {
    return (obj.nickname || obj.groupName)?.startsWith("points_");
  }

  /**
   * 预设线
   */
  isYsLine(obj, isLine) {
    if (isLine === obj.isSphere) {
      return false;
    }
    return this.isYsLineName(
      obj.nickname || obj.groupName || obj.userData.nickname
    );
  }

  isOtherLine(obj) {
    return obj.nickname?.startsWith("zyx_");
  }

  isCircle(obj) {
    return obj.nickname?.startsWith("circle_");
  }
  /**
   * 判断是否面
   */
  isFace(object) {
    return object?.material?.type === "MeshPhongMaterial";
  }

  /**
   * 判断是否线
   */
  isLine(object, filter = (obj) => true) {
    return (
      (object?.material?.type === "LineMaterial" ||
        this.isModelEdge(object) ||
        this.isYsLine(object, true) ||
        this.isCircle(object)) &&
      filter(object)
    );
  }

  /**
   * 判断是否球体
   */
  isSphere(object) {
    return object?.geometry?.type === "SphereGeometry";
  }
  /**
   * 预设线名称
   */
  isYsLineName(name) {
    return name?.match(
      /^curve_|^brokenLine_|^singleSpiralLine_|^doubleHelixLine_|^zyx_/
    );
  }
  /**
   * 创建网格助手(网格平面)
   * @param size
   * @param divisions
   * @param centerLineColor
   * @param gridColor
   */
  createGridHelper(
    size = 10,
    divisions = 10,
    centerLineColor = 0x444444,
    gridColor = 0x888888
  ) {
    // size -- 网格的大小。默认值为 10。
    // divisions -- 网格中的分割数。默认值为 10。
    // centerLineColor -- 中心线的颜色。这可以是Color、十六进制值和 CSS-Color 名称。默认为 0x444444
    // gridColor -- 网格线的颜色。这可以是Color、十六进制值和 CSS-Color 名称。默认为 0x888888
    this.gridHelper = new THREE.GridHelper(
      size,
      divisions,
      centerLineColor,
      gridColor
    );
    return this.gridHelper;
  }
  /**
   * 更新指针缓存坐标
   */
  updatePointer(e) {
    const { x, y } = this.getPosition(e);
    this.pointer.x = x;
    this.pointer.y = y;
    this.clientX = e.clientX;
    this.clientY = e.clientY;
  }
  /**
   * 创建网格平面坐标轴
   * @param planeMode 参照PlaneModeEnum
   * @param length 坐标boundingBox
   */
  createPlaneAxes(
    planeMode = PlaneModeEnum.planeXY,
    length = this.state.modelLong
  ) {
    const positions: number[] = [];
    const colors: any[] = [];
    const points: THREE.Vector3[] = [
      new THREE.Vector3(0, 0, 0),
      new THREE.Vector3(length, 0, 0),
      new THREE.Vector3(0, 0, 0),
      new THREE.Vector3(0, 0, -length),
    ];

    // x、y、z => 红、绿、蓝
    const redColor = new THREE.Color("red");
    const greenColor = new THREE.Color("green");
    const blueColor = new THREE.Color("blue");

    let axesUpColor, axesRightColor;
    if (planeMode.match(/XY/)) {
      axesUpColor = redColor;
      axesRightColor = greenColor;
    } else if (planeMode.match(/XZ/)) {
      axesUpColor = redColor;
      axesRightColor = blueColor;
    } else if (planeMode.match(/YZ/)) {
      axesUpColor = blueColor;
      axesRightColor = greenColor;
    }

    for (let i = 0; i < points.length; i++) {
      const point = points[i];
      positions.push(point.x, point.y, point.z);
      if (i < 2) {
        colors.push(axesUpColor.r, axesUpColor.g, axesUpColor.b);
      } else {
        colors.push(axesRightColor.r, axesRightColor.g, axesRightColor.b);
      }
    }

    const segmentsGeometry = new LineSegmentsGeometry();
    segmentsGeometry.setPositions(positions);
    segmentsGeometry.setColors(colors);

    const matLine = new LineMaterial({
      color: 0xffffff,
      linewidth: 4, // in world units with size attenuation, pixels otherwise
      // worldUnits: true,
      vertexColors: true,

      // resolution:  // to be set by renderer, eventually
      alphaToCoverage: true,
    });
    matLine.resolution.set(window.innerWidth, window.innerHeight);

    const segments = new LineSegments2(segmentsGeometry, matLine);
    segments.computeLineDistances();
    segments.scale.set(1, 1, 1);

    return segments;
  }
  /**
   * 创建帮助平面
   * @param planeMode 参照PlaneModeEnum
   * @param {THREE.Vector3} diy
   */
  createHelpPlane(planeMode, diy) {
    // 创建网格平面
    const gridHelperSmall = this.createGridHelper(
      this.state.modelLong * 2,
      60,
      0xa2a2a2,
      0xa2a2a2
    );
    const gridHelper = this.createGridHelper(
      this.state.modelLong * 2,
      10,
      0x000000,
      0x000000
    );

    // 创建网格平面坐标轴(默认和自定义都有)
    let planeAxes;
    if (planeMode.match(/XY|YZ|XZ/)) {
      planeAxes = this.createPlaneAxes(planeMode);
      // 自定义原点坐标
      if (!planeMode.match(/diy/i)) {
        diy = camCenter;
      }
    }
    const axesGroup = new THREE.Group();
    axesGroup.add(gridHelperSmall);
    axesGroup.add(gridHelper);
    if (planeAxes) {
      axesGroup.add(planeAxes);
    }
    axesGroup.updateMatrix();
    axesGroup.updateMatrixWorld(true);

    if (
      [PlaneModeEnum.planeXY, PlaneModeEnum.planeDiyXY].includes(
        this.curPlaneMode
      )
    ) {
      axesGroup.rotateX(Math.PI / 2);
      axesGroup.position.copy(diy.clone());
      axesGroup.userData.diyNormal = new THREE.Vector3(0, 0, 1);
    } else if (
      [PlaneModeEnum.planeXZ, PlaneModeEnum.planeDiyXZ].includes(
        this.curPlaneMode
      )
    ) {
      axesGroup.rotateZ(Math.PI);
      axesGroup.rotateY(Math.PI);
      axesGroup.position.copy(diy.clone());
      axesGroup.userData.diyNormal = new THREE.Vector3(0, 1, 0);
    } else if (
      [PlaneModeEnum.planeYZ, PlaneModeEnum.planeDiyYZ].includes(
        this.curPlaneMode
      )
    ) {
      axesGroup.rotateX(Math.PI / 2);
      axesGroup.rotateZ(Math.PI / 2);
      axesGroup.position.copy(diy.clone());
      axesGroup.userData.diyNormal = new THREE.Vector3(1, 0, 0);
    } else if (this.curPlaneMode === PlaneModeEnum.curveTangentPlane) {
      axesGroup.lookAt(this.state.centerPoint.normal);
      axesGroup.rotateX(Math.PI / 2);
      axesGroup.position.copy(diy.clone());
      axesGroup.userData.diyNormal = this.state.centerPoint.normal;
    } else if (this.curPlaneMode === PlaneModeEnum.curveNormalPlane) {
      axesGroup.lookAt(this.state.centerPoint.normal);
      axesGroup.rotateX(Math.PI / 2);
      axesGroup.position.copy(diy.clone());
      axesGroup.userData.diyNormal = this.state.centerPoint.normal;
    }

    axesGroup.updateMatrix();
    axesGroup.updateMatrixWorld(true);
    return axesGroup;
  }
  /**
   * 创建网格平面
   */
  createGridPlane(planeMode = this.curPlaneMode) {
    if (this.gridHelper) return;

    const diy = this.state.centerPoint.xyz ?? camCenter;
    this.diyPoint = diy.clone();

    this.gridHelper = this.createHelpPlane(planeMode, diy);
    this.gridHelper.userData.isHelper = true;
    this.gridHelper.renderOrder = RenderOrderEnum.grid;
    commonfunc.getScene().add(this.gridHelper);
    this.requestRender();
  }
  /**
   * 更新网格平面
   */
  updateGridPlane(planeMode) {
    if (this.gridHelper) {
      this.removeGridPlane();
    }
    this.createGridPlane(planeMode);
  }
  /**
   * 删除网格平面
   */
  removeGridPlane() {
    if (this.gridHelper) {
      commonfunc.removeSceneObj(this.gridHelper);
      this.gridHelper = null;
      this.requestRender();
    }
  }
  /**
   * 参考平面后处理
   */
  pointModalCallback() {
    // 参考平面绘制完毕
    this.curPrePlaneMode = null;
    // 清除回车事件
    enterCallback = null;
    // 渲染参考平面
    this.updateGridPlane(this.curPlaneMode);
    // 清除对应图形
    const arr = [this.state.centerPoint.object].filter((i) => i);
    arr.forEach((i) => (i!.visible = false));
    commonfunc.removeSceneObjByArray(arr);
    this.state.centerPoint.object = null;
    // 清除消息
    // this.$message.destroy();
  }
  /**
   * 获取球体半径
   */
  getSphereRadius(radius) {
    if (this.state.modelLong >= 170 && this.state.modelLong < 500) {
      return 2;
    }
    if (this.state.modelLong >= 500 && this.state.modelLong <= 700) {
      return 3;
    }
    if (this.state.modelLong >= 50000) {
      return 500;
    }
    return radius;
  }
  /**
   * 绘制小球
   */
  drawSphere(
    point,
    isCenterPoint = true,
    radius = 1,
    groupName = this.nickname
  ) {
    if (!point) return;
    if (!this.sphereCount) this.sphereCount = 0;
    this.sphereCount++;
    radius = this.getSphereRadius(radius);
    const geometry = new THREE.SphereGeometry(radius, 100, 100);
    const material = new THREE.MeshBasicMaterial({ color: ColorEnum.yellow });
    const sphere = new THREE.Mesh(geometry, material);
    sphere.userData.groupName = groupName;
    sphere.position.copy(new THREE.Vector3(point.x, point.y, point.z));
    sphere.userData.isCenterPoint = !!isCenterPoint; // 是中心点
    sphere.userData.isTemporary = true; // 是临时的
    sphere.userData.isSphere = true;
    sphere.visible = false;
    sphere.visible = this.originVisible;
    commonfunc.getScene().add(sphere);
    this.requestRender();
    return sphere;
  }
  /**
   * 参考平面模式前处理
   * @param {*} e
   */
  onPrePlaneHandler(e) {
    enterCallback = (event) => {
      preventDefaults(event);
      if (!this.state.centerPoint.xyz) {
        return;
      }
      this
        .pointModalCallback
        // this.state.centerPoint.xyz ? this.state.centerPoint.start?.position : {}
        ();
      mitt.emit("addPlaneEnd", {
        plane: this.gridHelper,
        point: this.state.centerPoint.xyz,
      });
    };

    // 切平面只过滤面，法平面只过滤线
    let intersects: any = this.getCanvasIntersects(
      e,
      commonfunc.getScene(),
      this.state.curCamera,
      commonfunc.getCanvas()
    );
    if (this.curPlaneMode === PlaneModeEnum.curveNormalPlane) {
      // 法平面只过滤线
      intersects = intersects?.filter((item) => this.isLine(item.object));
    } else if (this.curPlaneMode === PlaneModeEnum.curveTangentPlane) {
      // 切平面只过滤面
      intersects = intersects?.filter((item) => this.isFace(item.object));
    }

    // mouseclick事件中，有相交点就绘制点
    if (intersects[0]?.point) {
      // logger.log('onPrePlaneHandler', intersects[0]);
      if (this.state.centerPoint.object) {
        commonfunc.removeSceneObjByArray([this.state.centerPoint.object]);
      }
      let centerPoint = this.state.centerPoint;
      if (this.curPlaneMode.match(/XY|YZ|XZ/)) {
        centerPoint.object = this.drawSphere(
          intersects[0].point,
          undefined,
          2,
          "center"
        );
        centerPoint!.object!.visible = true;
        centerPoint.xyz = intersects[0].point;
        this.setState({
          centerPoint: centerPoint,
        });
      } else if (this.curPlaneMode === PlaneModeEnum.curveTangentPlane) {
        centerPoint.object = this.drawSphere(
          intersects[0].point,
          undefined,
          2,
          "center"
        );
        centerPoint!.object!.visible = true;
        centerPoint.xyz = intersects[0].point;
        centerPoint.normal = intersects[0]!.face!.normal;
        this.setState({
          centerPoint: centerPoint,
        });
        // this.$message.destroy();
        // this.$message.info('回车后显示参考平面', 0);
      } else if (this.curPlaneMode === PlaneModeEnum.curveNormalPlane) {
        centerPoint.object = this.drawSphere(
          intersects[0].point,
          undefined,
          2,
          "center"
        );
        centerPoint!.object!.visible = true;
        centerPoint.xyz = intersects[0].point;
        const pointOnLine = intersects[0].pointOnLine;
        const arr =
          intersects[0].object.geometry.attributes.instanceStart.data.array;
        centerPoint.normal = null;

        for (let i = 0; i < arr.length; i = i + 3) {
          if (
            pointOnLine.x === arr[i] &&
            pointOnLine.y === arr[i + 1] &&
            pointOnLine.z === arr[i + 2]
          ) {
            centerPoint.normal = new THREE.Vector3(
              arr[i + 3] - arr[i - 3],
              arr[i + 4] - arr[i - 2],
              arr[i + 5] - arr[i - 1]
            );
            // logger.log('normal', this.state.centerPoint.normal);
          }
        }
        if (!centerPoint.normal) {
          centerPoint.normal = new THREE.Vector3(
            arr[arr.length - 3] - arr[0],
            arr[arr.length - 2] - arr[1],
            arr[arr.length - 1] - arr[2]
          );
          // logger.log('normal', this.state.centerPoint.normal);
        }
        this.setState({
          centerPoint: centerPoint,
        });
        // this.$message.destroy();
        // this.$message.info('回车后显示参考平面', 0);
      } else {
        // this.$message.destroy();
        // this.$message.info('回车后显示参考平面', 0);
      }
    }
  }
  getCurrentYSXCount(type) {
    let num = 0;
    const ysxList = Object.entries(this.curvesMap)
      .map((item) => {
        return item[0];
      })
      .filter((item) => item.startsWith(type));
    for (const item of ysxList) {
      const [_, count] = item.split("_");
      if (+count > num) {
        num = parseInt(count);
      }
    }
    return +num;
  }
  /**
   * 根据昵称取类型
   * @param nickname 昵称
   */
  getTypeByNickname(nickname) {
    return nickname?.replace(/_.*$/, "");
  }
  /**
   * 停止绘制
   */
  stopDrawn() {
    this.curDraw = "";
    this.drawing = false;
  }
  /**
   * 获取场景所有变径点
   * @param {Function=} condition
   */
  getSceneAllBjPoint(condition = (child) => child) {
    const group = commonfunc.createOrUpdateGroup(BJ_POINT_GROUP);
    if (!group) return [];
    return group.children.filter((child) => condition(child));
  }
  /**
   * 更新场景预设线
   * @param {Line2} ysLine
   * @param {Function=} filter
   */
  updateSceneYsLine(ysLine, filter = (child) => child) {
    const ysLineGroup = commonfunc.createOrUpdateGroup(YS_LINE_GROUP);
    if (ysLine) {
      // 插入新数据
      ysLineGroup.children.push(ysLine);
    }
    ysLineGroup.children = ysLineGroup.children.filter(filter);
    this.requestRender();
  }
  /**
   * 发出更新曲线数据
   */
  emitCurveData(key) {
    const points = this.curvesMap[this.nickname]?.clickPoints.map((point) =>
      this.getPoint(point.clone())
    );
    this.$emit("updateCurve", {
      key: this.state.curActiveObj?.key || key,
      nickname: this.nickname,
      value: points,
    });
    // this.$emit('updateDiyShapeList', {
    // 	key: this.nickname,
    // 	value: points,
    // 	type: this.getTypeByNickname(this.nickname)
    // });
  }
  /**
   * 制作曲线
   */
  makeCurve(pointVectors, groupName, isTemporary) {
    let curve;
    let curvePoints;
    const drawType = this.getTypeByNickname(groupName) ?? DrawEnum.curve;
    if (drawType === DrawEnum.curve) {
      curve = new THREE.CatmullRomCurve3(pointVectors, false, "centripetal");
      curvePoints = curve.getPoints(pointVectors.length >= 6 ? 100 : 50);
    } else if (drawType === DrawEnum.brokenLine) {
      curve = new THREE.Shape(pointVectors);
      curve.autoClose = false;
      curvePoints = pointVectors;
    } else {
      curve = new THREE.CatmullRomCurve3(pointVectors, false, "centripetal");
      curvePoints = pointVectors;
    }

    const geometry = new THREE.BufferGeometry().setFromPoints(curvePoints);
    const lineGeometry: any = new LineGeometry();

    lineGeometry.setPositions(geometry.attributes.position.array);
    let color = ColorEnum.black;
    if (["ys_line"].includes(this.state.curActiveObj?.key)) {
      //some: 判断数组中是否有满足条件的元素
      const hasYsLineActivate = this.state.curActiveObj.extra.some(
        (extraItem) => extraItem.ysLineActivate
      );
      if (hasYsLineActivate) {
        color = ColorEnum.cyanBlue;
      }
    }
    const lineMaterial = getLineMaterial(color, commonfunc.getCanvas(), 2);
    const line: any = new Line2(lineGeometry, lineMaterial);
    line.isCurve = true;
    line.visible = this.originVisible;
    // line.nickname = this.nickname;
    line.nickname = groupName;
    line.groupName = groupName;
    line.isTemporary = isTemporary;

    this.updateSceneYsLine(line);
    this.requestRender();

    return { curve, line };
  }
  /**
   * 确认绘制曲线
   */
  confirmDrawCurve(pointVector: any = null, isTemporary = true) {
    const pointMap = this.curvesMap[this.nickname];
    if (!pointMap) return;

    const filter = (child) => child && child.nickname !== this.nickname;
    this.updateSceneYsLine(null, filter);

    const clickPoints = pointMap.clickPoints || [];
    const pointVectors = clickPoints.map((p) => p.clone());
    if (pointVector) pointVectors.push(pointVector.clone());

    if (pointVectors.length < 2) return;

    const res = this.makeCurve(pointVectors, this.nickname, isTemporary);
    this.requestRender();

    return res;
  }
  /**
   * 鼠标移动绘制曲线
   */
  mouseMoveDrawCurve({ clientX, clientY }) {
    this.clientX = clientX;
    this.clientY = clientY;
    const pointVector = this.getCurrPoint({ clientX, clientY });
    if (!pointVector) return;
    this.confirmDrawCurve(pointVector, true);
  }
  /**
   * 按列表删除相交对象
   */
  removeIntersectObjByList(spheres: any[] = []) {
    spheres.forEach((sphere: any) => {
      this.intersectObjects = this.intersectObjects.filter(
        (obj) => obj.uuid !== sphere.uuid
      );
    });
  }
  /**
   * 按预设线名称删除场景球体
   */
  removeSceneSphereByYsLines(ysLineNameList) {
    ysLineNameList = ysLineNameList || [];
    let spheres: any[] = [];
    ysLineNameList.forEach((ysLineName) => {
      const { spheres: objs } =
        commonfunc.getYsLineObjectAndSphereByGroupName(ysLineName);
      spheres.push(...objs);
    });
    commonfunc.removeSceneObjByArray(spheres);
    this.removeIntersectObjByList(spheres);
    this.requestRender();
    spheres = [];
  }
  /**
   * 按组名删除场景预设线
   * @param {String} groupName
   * @param {Function=} filter
   */
  removeSceneYsLineByGroupName(groupName, filter = (child) => child) {
    const ysLineGroup = commonfunc.getGroupByName(YS_LINE_GROUP);
    if (ysLineGroup) {
      const needsUpdateChildren = ysLineGroup.children.filter(
        (child: any) => groupName !== child.nickname
      );
      // 更新数据
      ysLineGroup.children = needsUpdateChildren.filter(filter);

      // 删除预设线对应的小球
      this.removeSceneSphereByYsLines([groupName]);

      if (this.isYsLineName(groupName)) {
        // 删除拾取列表中对应的预设线
        raycasterObjs = raycasterObjs.filter(
          (obj: any) => groupName !== obj.nickname
        );
        // 删除缓存中的预设线
        delete this.curvesMap[groupName];
      }

      this.requestRender();
    }
  }
  /**
   * 分离选定
   */
  detachSelected(drawControl: any = null) {
    drawControl && drawControl.detach();
    drawControl = null;
    this.currentActiveItem = null;
  }
  rebackAdd(prevFunc, rebackFunc) {
    rebackList.push(() => {
      const reback = () => {
        this.currentFunc = prevFunc;
        rebackFunc && rebackFunc();
      };

      reback();
      prevFunc && prevFunc();
    });
  }

  /**
   * 初始化曲线回车和回退事件
   */
  initCurveEnterAndRollbackEvent() {
    enterCallback = (event) => {
      preventDefaults(event);
      this.stopDrawn();
      this.detachSelected();
      this.$emit("clearDraw");
      if (this.state.curControl) {
        let tmp = this.state.curControl;
        tmp.enabled = true;
        this.setState({
          curControl: tmp,
        });
      }

      this.inited = false;
      this.drawing = false; // 绘制结束
      if (commonfunc.getRenderer()?.domElement) {
        removeEventHandler(
          commonfunc.getRenderer().domElement,
          "mousemove",
          this.throttleMouseMoveHandler
        );
        this.throttleMouseMoveHandler = null;
      }

      const pointMap = this.curvesMap[this.nickname];
      if (!pointMap) return;

      const res = this.confirmDrawCurve(null, false);
      if (res) {
        raycasterObjs.push(res.line);
        this.requestRender();
      }
      if (!this.isInitDrawCurve) {
        this.emitCurveData("ys_line");
      }
      this.isInitDrawCurve = false;

      // this.initCurveDrawEvent();
      this.detachSelected();
      enterCallback = null;
    };

    escCallback = () => {
      // 分离选定
      this.detachSelected();
      // 清除绘制线
      if (
        [DrawEnum.curve, DrawEnum.brokenLine].includes(this.curDraw) &&
        this.curvesMap[this.nickname]
      ) {
        const spheres = this.curvesMap[this.nickname].spheres;
        if (spheres.length) {
          this.removeSceneYsLineByGroupName(spheres[0].groupName);
        }
      }
    };

    // 回退至上一步
    // ctrlZCallback = () => {
    // 	// 绘制完毕后不允许回退
    // 	if (!this.drawing) return;

    // 	if (this.curvesMap[this.nickname].clickPoints.length > 1) {
    // 		this.curvesMap[this.nickname].clickPoints.pop();
    // 		const sphere = this.curvesMap[this.nickname].spheres.pop();
    // 		this.getScene().remove(sphere);
    // 		raycasterObjs = raycasterObjs.filter(obj => obj.uuid !== sphere.uuid);
    // 		this.mouseMoveDrawCurve({ clientX: this.clientX, clientY: this.clientY });
    // 		this.requestRender();
    // 	} else {
    // 		this.$message.info('已回退到最后一步啦!');
    // 	}
    // };
  }

  /**
   * 获取当前点坐标
   *  @param event
   *  @return {THREE.Vector3}
   */
  getCurrPoint(event, filter = (xx) => true) {
    const intersects = this.getCanvasIntersects(
      event,
      commonfunc.getScene(),
      this.state.curCamera,
      commonfunc.getCanvas()
    ).filter(filter);
    return intersects[0]?.point;
  }
  /**
   * 绘制曲线
   */
  drawCurve(nickname, clickPoints, isInitDrawCurve = false) {
    return new Promise(async (resolve) => {
      this.isInitDrawCurve = isInitDrawCurve;

      this.nickname = nickname || this.nickname;

      const resetCurvesMap = () => {
        raycasterObjs = raycasterObjs.filter(
          (item: any) =>
            item.nickname !== nickname && item.groupName !== nickname
        );
        commonfunc.removeSceneObj(this.curvesMap[this.nickname]?.spheres);
        this.curvesMap[this.nickname] = {
          spheres: [],
          clickPoints: [],
        };
      };
      const commonHandler = (pointVector, isTemporary) => {
        if (
          [DrawEnum.curve, DrawEnum.brokenLine].includes(
            this.getTypeByNickname(this.nickname)
          )
        ) {
          const sphere = this.drawSphere(pointVector);
          if (sphere) {
            sphere.userData.isTemporary = isTemporary;
            raycasterObjs.push(sphere);
            this.curvesMap[this.nickname].spheres.push(sphere);
            this.curvesMap[this.nickname].clickPoints.push(pointVector);
          }
        } else {
          this.curvesMap[this.nickname].clickPoints.push(pointVector);
        }
      };

      const setCount = () => {
        if (this.nickname && this.nickname.includes("_")) {
          [
            DrawEnum.curve,
            DrawEnum.brokenLine,
            DrawEnum.singleSpiralLine,
            DrawEnum.doubleHelixLine,
            DrawEnum.circle,
          ].forEach((i) => {
            if (this.nickname.startsWith(i)) {
              this[i + "Count"] = this.getCurrentYSXCount(i);
            }
          });
        }
      };

      if (isArray(clickPoints) && clickPoints.length) {
        resetCurvesMap();
        for (const point of clickPoints) {
          const pointVector = new THREE.Vector3(point.x, point.y, point.z);
          commonHandler(pointVector, false);
        }
        this.initCurveEnterAndRollbackEvent();
        enterCallback();
      } else {
        if (!this.curvesMap[this.nickname] || !this.drawing) {
          resetCurvesMap();
        }
        this.drawing = true;
        const pointVector = this.getCurrPoint({
          clientX: this.clientX,
          clientY: this.clientY,
        });
        if (pointVector) {
          this.rebackAdd(() => {
            if (this.curvesMap[this.nickname]?.clickPoints.length > 1) {
              this.curvesMap[this.nickname].clickPoints.pop();
              const sphere = this.curvesMap[this.nickname].spheres.pop();
              commonfunc.removeSceneObj(sphere);
              raycasterObjs = raycasterObjs.filter(
                (obj) => obj.uuid !== sphere.uuid
              );
              this.mouseMoveDrawCurve({
                clientX: this.clientX,
                clientY: this.clientY,
              });
              this.requestRender();
            } else {
              // this.$message.info('已回退到最后一步啦!');
            }
          }, undefined);
          commonHandler(pointVector, null);
          if (!this.inited && this.curDraw) {
            this.inited = true;
            this.throttleMouseMoveHandler = throttle(
              this.mouseMoveDrawCurve,
              10
            );
            addEventHandler(
              commonfunc.getRenderer().domElement,
              "mousemove",
              this.throttleMouseMoveHandler,
              true
            );
            this.initCurveEnterAndRollbackEvent();
          }
        }
      }
      setCount();
      return resolve(null);
    });
  }
  /**
   * 获取点坐标
   * @param vector3
   * @return {{}}
   */
  getPoint(vector3) {
    return pick(vector3, ["x", "y", "z"]);
  }
  /**
   * 当canvas不占满整屏时射线拾取存在偏差，获取点击管道对象
   * @param event 事件对象
   */
  getPipeLineIntersects(event) {
    if (event && event.preventDefault) {
      event.preventDefault();
    }
    const canvas = commonfunc.getCanvas();
    // 获取元素的大小及其相对于视口的位置
    const getBoundingClientRect = canvas.getBoundingClientRect();
    // 屏幕坐标转标准设备坐标
    const x =
      ((event.clientX - getBoundingClientRect.left) / canvas.offsetWidth) * 2 -
      1; // 标准设备横坐标
    const y =
      -((event.clientY - getBoundingClientRect.top) / canvas.offsetHeight) * 2 +
      1; // 标准设备纵坐标
    const vector = new THREE.Vector3(x, y, 0.5); // 标准设备坐标
    // 创建射线投射器对象
    const raycaster: any = new THREE.Raycaster();
    raycaster.params.Line = { threshold: 4 };
    raycaster.params.Line2 = { threshold: 8 };
    raycaster.params.Points = { threshold: 4 };
    raycaster.setFromCamera(vector, this.state.curCamera);
    const objects: any[] = [];
    const children = commonfunc.getSceneAllResultObjs(
      (child) => child.groupName === waterCoolingResultKeyMap.pipeline
    );
    const children2 = this.getSceneAllBjPoint();
    // logger.log('MoldView getPipeLineIntersects children2:', children2);
    if (children?.length) objects.push(...children, ...children2);
    // 返回射线选中的对象 第二个参数如果不填 默认是false
    const intersects = raycaster.intersectObjects(objects);
    // logger.log('MoldView getPipeLineIntersects intersects:', intersects);
    if (intersects.some((i) => i.object.groupName?.match("points_group"))) {
      return [];
    }
    // 返回选中的对象数组
    return intersects.filter((i) => !i.object.groupName?.match("points_group"));
  }
  /**
   * 绘制圆
   */
  async drawCircle(point, intersect) {
    if (!this.direction) {
      // this.$modal.warning({ content: '请先选择视图模式' });
      return;
    }

    if (this.circleSetting.point) {
      return;
      // this.tempCurvesGroup.clear();
      // this.removeSceneObjByArray([this.circleSetting.point]);
    }
    const sphere = this.drawSphere(point, true);
    this.circleSetting = {
      showSetting: true,
      _point: point,
      point: sphere,
      newPoint: null,
      drawResult: null,
      radius: 10,
    };
    this.curveCount++;

    // switch (this.direction) {
    // 	case ViewEnum.front:
    // 	case ViewEnum.back: {
    // 		this.setPlaneMode(PlaneModeEnum.planeDiyXZ, point, new THREE.Vector3(0, 0, 1));
    // 		break;
    // 	}
    // 	case ViewEnum.left:
    // 	case ViewEnum.right: {
    // 		this.setPlaneMode(PlaneModeEnum.planeDiyYZ, point, new THREE.Vector3(1, 0, 0));
    // 		break;
    // 	}
    // 	case ViewEnum.top:
    // 	case ViewEnum.bottom: {
    // 		this.setPlaneMode(PlaneModeEnum.planeDiyXY, point, new THREE.Vector3(0, 1, 0));
    // 		break;
    // 	}
    // 	case ViewEnum.default: {
    // 		this.setPlaneMode(PlaneModeEnum.curveTangentPlane, point, intersect?.face?.normal ?? new THREE.Vector3(0, 0, 1));
    // 		break;
    // 	}
    // 	default:
    // 		this.$message.warning('请选择视图');
    // 		// logger.error('请选择视图');
    // 		break;
    // }

    escCallback = () => {
      // this.$message.destroy();
      this.stopDrawn();
      this.detachSelected();
      this.$emit("clearDraw");
      commonfunc.removeSceneObjByArray([
        this.circleSetting.drawResult.circle,
        this.circleSetting.point,
      ]);
      this.circleSetting = {
        showSetting: false,
        _point: null,
        point: null,
        newPoint: null,
        drawResult: null,
        radius: 10,
      };
      this.tempCurvesGroup.clear();
      delete this.curvesMap[this.nickname];
      let tmp = this.state.curControl;
      if (tmp) {
        tmp.enabled = true;
        this.setState({
          curControl: tmp,
        });
      }
      this.inited = false;
      this.drawing = false; // 绘制结束
      // if (this.getRenderer()?.domElement) {
      // 	removeEventHandler(this.getRenderer().domElement, 'pointermove', onMousemove);
      // }
      // this.setPlaneMode();
      this.requestRender();
      enterCallback = null;
      escCallback = null;
    };

    enterCallback = (event) => {
      // this.$message.destroy();
      preventDefaults(event);
      this.stopDrawn();
      this.detachSelected();
      this.$emit("clearDraw");
      let tmp = this.state.curControl;
      if (tmp) {
        tmp.enabled = true;
        this.setState({
          curControl: tmp,
        });
      }

      this.inited = false;
      this.drawing = false; // 绘制结束
      // if (this.getRenderer()?.domElement) {
      // 	removeEventHandler(this.getRenderer().domElement, 'pointermove', onMousemove);
      // }

      const pointMap = this.curvesMap[this.nickname];
      if (!pointMap) return;

      if (this.circleSetting.drawResult) {
        this.drawCurve(
          this.nickname,
          this.circleSetting.drawResult.circlePoints
        );
        this.tempCurvesGroup.clear();
        commonfunc.removeSceneObjByArray([
          this.circleSetting.drawResult.circle,
          sphere,
        ]);
        // logger.log('drawCircle enterCallback', this.curvesGroup, this.tempCurvesGroup, pointMap.clickPoints);

        // this.setPlaneMode();
        this.requestRender();
        // if (!this.isInitDrawCurve) {
        // 	this.emitCircleData();
        // }
        this.isInitDrawCurve = false;
      }

      this.circleSetting = {
        showSetting: false,
        point: null,
        newPoint: null,
        drawResult: null,
        radius: 10,
      };
      this.detachSelected();
      escCallback = null;
      enterCallback = null;
    };

    // const onMousemove = (event) => {
    // 	const scene = this.getScene();
    // 	for (const child of scene.children) {
    // 		if (child && child.isTemporary && !child.isCenterPoint) {
    // 			sleep(1, () => scene.remove(child));
    // 		}
    // 	}

    // 	this.circleSetting.newPoint = null;
    // 	this.circleSetting.drawResult = {
    // 		circlePoints: [],
    // 	};

    // 	let intersects = this.getCanvasIntersects(event, scene, this.curCamera, this.getCanvas());
    // 	intersects = intersects.filter(i => i.object.type === 'GridHelper');
    // 	if (intersects.length) {
    // 		this.circleSetting.newPoint = this.getPoint(intersects[0].point);
    // 		sleep(1, () => {
    // 			if (point && this.circleSetting.newPoint) {
    // 				this.circleSetting.drawResult = this.drawCircleByCondition(point, this.circleSetting.newPoint);
    // 			}
    // 		});
    // 	}
    // };
    // this.getRenderer().domElement.addEventListener('pointermove', onMousemove, false);

    this.requestRender();

    // this.$message.destroy();
    // this.$message.info('在弹窗修改半径，按【Enter回车】绘制完成，按【ESC】取消绘制', 0);
  }
  /**
   * 更新场景变径点
   * @param sphere
   * @param {Function=} filter
   */
  updateSceneBjPoint(sphere, filter = (child) => child) {
    const bjPointGroup = commonfunc.getGroupByName(BJ_POINT_GROUP);
    if (bjPointGroup) {
      if (sphere) {
        // 更新数据
        bjPointGroup.children.push(sphere);
      }
      bjPointGroup.children = bjPointGroup.children.filter(filter);
      this.requestRender();
    }
  }
  /**
   * 绘制变径点小球
   */
  drawBjPointSphere(point, { nickname = "", groupName = "", radius = 2 } = {}) {
    if (!point) return;
    radius = this.getSphereRadius(radius);
    const geometry = new THREE.SphereGeometry(radius, 100, 100);
    const material = new THREE.MeshBasicMaterial({
      color: ColorEnum.yellow,
      polygonOffset: true, // 是否使用多边形偏移，默认值为false
      // 当这两个参数都为负时（深度减小），网格将被拉向摄影机(位于前面);
      // 当两个参数都为正（增加深度）时，网格会被推离摄影机(会落在后面)
      polygonOffsetFactor: -1, // 偏移系数，与相机距离减2
      polygonOffsetUnits: -40, // 偏移的单位
    });
    const sphere: any = new THREE.Mesh(geometry, material);
    sphere.nickname = nickname;
    sphere.groupName = groupName;
    sphere.position.copy(new THREE.Vector3(point.x, point.y, point.z));
    sphere.isSphere = true;
    sphere.visible = true;
    sphere.renderOrder = RenderOrderEnum.point;

    this.updateSceneBjPoint(sphere);

    return sphere;
  }
  /**
   * 绘图处理
   * @param e
   */
  onDrawHandler(e) {
    if ([DrawEnum.curve, DrawEnum.brokenLine].includes(this.curDraw)) {
      // 绘制曲线
      // if (!this.state.curActiveObj || this.state.curActiveObj.key !== 'ys_line') {
      // 	this.$message.warn('请先点选预设线参数');
      // 	return;
      // }
      this.drawCurve(null, null);
    } else if (this.curDraw === DrawEnum.point) {
      // 绘制点
      if (
        !this.state.curActiveObj ||
        this.state.curActiveObj.key !== "bj_point"
      ) {
        // this.$message.info("请先点选变径点参数");
        return;
      }
      if (this.state.curActiveObj.key === "bj_point") {
        // 变径点只能在管线上绘制
        const intersects = this.getPipeLineIntersects(e);
        if (intersects.length) {
          this.pointCount++;
          const point = intersects[0].point;
          const nameSuffix = intersects[0].object.nickname.replace(
            waterCoolingResultKeyMap.pipeline,
            ""
          );
          const groupName = "points_group" + nameSuffix;
          const nickname = "point_" + this.pointCount;
          this.drawBjPointSphere(point.clone(), { nickname, groupName });
          this.$emit("updateBjPoint", {
            nickname,
            groupName,
            value: pick(point.clone(), ["x", "y", "z"]),
          });
        } else {
          // this.$message.info("变径点只能在管线上绘制，并且需避开其他变径点");
        }
      }
    } else if (this.curDraw === DrawEnum.circle) {
      // 绘制圆
      const intersects = this.getIntersects(this.clientX, this.clientY);
      if (intersects.length) {
        const point = intersects[0].point;
        this.drawCircle(this.getPoint(point), intersects[0]);
      }
    } else if (
      [DrawEnum.singleSpiralLine, DrawEnum.doubleHelixLine].includes(
        this.curDraw
      )
    ) {
      // 绘制圆
      const intersects = this.getIntersects(this.clientX, this.clientY);
      if (intersects.length) {
        const point = intersects[0].point;
        this.drawCircularHelix(this.getPoint(point), intersects[0]);
      }
    }
  }

  /**
   * 画螺旋线下一步
   */
  drawCircularHelixDetail({
    position=null,
    direction=null,
    interval=0,
    radius=0,
    count=0,
    angle = null,
    trimTurnsNum=0,
  } = {}) {
    // 根据平面画圆（方向、位置一致）
    const circleGeo = drawCircleByPlane({ position, radius, count });
    if (angle) circleGeo.rotateZ(angle);

    // 根据法线方向、间隔(螺距)求当前方向
    const curDirection = setAmplitude(direction, interval);
    // 根据圆形几何体、当前方向、圈数、半径求几何体(eg: 3圈，按固定间隔，绘制3个圆，并返回)
    const geos = arrLinear(circleGeo, curDirection, trimTurnsNum, radius);

    // 创建一系列数字
    const results = range(interval, count);
    // logger.log('results: ', results);
    const vectors = setAmplitudeByList(direction, results);
    // logger.log('vectors: ', vectors);

    const points = [];
    // let index = 0;
    const spheres = [];
    for (const geo of geos) {
      const geoPoints = divide(geo);
      const movedPoints = move(geoPoints, vectors);
      points.push(...movedPoints);
      // if (showSphere) {
      // 	for (const movedPoint of movedPoints) {
      // 		const p = drawSphere(movedPoint, { radius: 0.5 });
      // 		spheres.push(p);
      // 	}
      // }
      // index++;
    }

    // if (showSphere) mainObject.add(...spheres);

    const lastPoint = points[points.length - 1]; // 最后一个坐标点

    const cirLine = drawLine(points, 1, geos[0]);

    // 销毁过渡用的geo
    // geometry.dispose();

    // 该语句默认在threeJs渲染的过程中执行, 如果想获得世界矩阵属性、世界位置属性等属性，需要手动更新
    cirLine.updateMatrixWorld(true);

    this.requestRender();

    function drawCircleByPlane({
      position=null,
      count=0,
      radius = 10,
      startAngle = 0,
      endAngle = 2 * Math.PI,
      clockwise = true,
    } = {}) {
      // 创建圆弧对象 ArcCurve
      // 参数：
      //  aX – 圆弧坐标原点X坐标，默认值为0。
      //  aY – 圆弧坐标原点Y坐标，默认值为0。
      //  radius – 圆弧半径。
      //  startAngle – 圆弧起始的角度。默认值为 0。
      //  endAngle – 圆弧终止的角度。默认值为 2 x Math.PI
      //  clockwise – 圆弧是否按顺时针方向绘制。默认为 false
      const curve = new THREE.ArcCurve(
        0,
        0,
        radius,
        startAngle,
        endAngle,
        clockwise
      );

      // getPoints是基类Curve的方法，返回一个vector2对象作为元素组成的数组
      // setFromPoints方法从points中提取数据改变几何体的顶点属性vertices
      const curvePoints = curve.getPoints(POINT_NUMBER * count);
      const geometry = new THREE.BufferGeometry().setFromPoints(curvePoints);
      const material = new THREE.LineBasicMaterial({
        color: ColorEnum.black,
        linewidth: 2,
      });
      const circle = new THREE.Line(geometry, material);

      // 执行lookAt方法之前，需要先设置circle的位置
      const origin = position;
      circle.position.copy(origin);
      // 设置circle对象看向的位置(位置向量和切线向量相加即为所需朝向的点向量)
      const lookAtVec = direction.clone().add(origin);
      circle.lookAt(lookAtVec);

      return circle;
    }

    function setAmplitude(vector3, amp) {
      const nor = vector3.clone().normalize(); // 变成法向量(归一化)
      const newVector3 = new THREE.Vector3(
        nor.x * amp,
        nor.y * amp,
        nor.z * amp
      );
      // const newVector3 = vector3.clone().multiplyScalar(amp); // 将向量与所传入的标量amp进行相乘
      return newVector3;
    }

    function setAmplitudeByList(direction, motions) {
      const points:THREE.Vector3[] = [];
      const dirNor = direction.clone().normalize(); // 变成法向量(归一化)
      for (const motion of motions) {
        const newVector3 = new THREE.Vector3(
          dirNor.x * motion,
          dirNor.y * motion,
          dirNor.z * motion
        );
        // const newVector3 = direction.clone().multiplyScalar(motion); // 将向量与所传入的标量amp进行相乘
        points.push(newVector3);
      }
      return points;
    }

    /**
     * 创建一系列数字
     * @param interval
     * @param steps
     * @return {*[]}
     */
    function range(interval, steps = 10) {
      const result:number[] = [];
      const initValue = interval / steps;
      for (let i = 0; i <= steps; i++) {
        result.push(initValue * i);
      }
      return result;
    }

    /**
     * 创建几何的线性阵列
     * @param G circle Geometry 圆形几何
     * @param D direction 方向
     * @param N turnsNum 圈数
     * @param R radius 半径
     * @return {Array<Object>} geos
     */
    function arrLinear(G, D, N, R) {
      const origin = G.position.clone();
      const rotation = G.rotation.clone();
      const radius = parseInt(R);

      const geos:any[] = [];

      const handler = (originPoint, p0, p1) => {
        const { circle } = drawCircleCurve(p0, p1, {
          radius: radius,
          turnsNum: N,
        });
        circle.rotation.copy(rotation);
        // mainObject.add(circle);
        geos.push(circle);
      };

      const p0 = origin.clone();
      for (let i = 0; i < N; i++) {
        let p1;
        if (i === 0) {
          p1 = p0.clone();
        } else {
          p1 = move([origin], [D])[0];
        }
        handler(origin, p0, p1);
      }

      return geos;
    }

    /**
     * 将曲线分成等长的段
     * @param curve
     * @return {*[]}
     */
    function divide(curve) {
      // 根据圆生成路径上控制点(10个,可控制数量)
      const points = pointsByCircleCurve(curve);
      return points;
    }

    /**
     *
     * @param curve 曲线几何体
     * @param isDrawSphere 是否绘制小球
     * @return {*[]}
     */
    function pointsByCircleCurve(curve, isDrawSphere = false) {
      // 调用localToWorld前需要先更新世界矩阵属性
      // 如果想获得世界矩阵属性、世界位置属性等属性，需要手动更新
      curve.updateMatrixWorld(true);

      const points :any[]= [];
      const positions = curve.geometry.attributes.position.array;
      for (let i = 0; i < positions.length; i += 3) {
        const x = positions[i + 0];
        const y = positions[i + 1];
        const z = positions[i + 2];
        // 本地坐标转世界坐标
        const point = curve.localToWorld(new THREE.Vector3(x, y, z));
        points.push(point);
      }

      // if (isDrawSphere) {
      // 	drawSphereByPoints(points, curve);
      // }

      return points;
    }

    function move(points, vectors) {
      const newPoints : THREE.Vector3[]= [];
      let index = 0;
      for (const point of points) {
        const motion = vectors[index];
        // 两点相加
        const v3 = point.add(motion);
        newPoints.push(new THREE.Vector3(v3.x, v3.y, v3.z));
        index++;
      }
      return newPoints;
    }

    function drawCircleCurve(
      startPoint,
      endPoint,
      {
        turnsNum=0,
        radius = 10,
        startAngle = 0,
        endAngle = 2 * Math.PI,
        clockwise = true,
      } = {}
    ) {
      // 创建圆弧对象 ArcCurve
      // 参数：
      //  aX – 圆弧坐标原点X坐标，默认值为0。
      //  aY – 圆弧坐标原点Y坐标，默认值为0。
      //  radius – 圆弧半径。
      //  startAngle – 圆弧起始的角度。默认值为 0。
      //  endAngle – 圆弧终止的角度。默认值为 2 x Math.PI
      //  clockwise – 圆弧是否按顺时针方向绘制。默认为 false
      const curve = new THREE.ArcCurve(
        0,
        0,
        radius,
        startAngle,
        endAngle,
        clockwise
      );

      // getPoints是基类Curve的方法，返回一个vector2对象作为元素组成的数组
      // setFromPoints方法从points中提取数据改变几何体的顶点属性vertices
      const curvePoints = curve.getPoints(POINT_NUMBER);
      const geometry = new THREE.BufferGeometry().setFromPoints(curvePoints);
      const material = new THREE.LineBasicMaterial({
        color: ColorEnum.black,
        linewidth: 2,
      });
      const circle = new THREE.Line(geometry, material);

      // 执行lookAt方法之前，需要先设置circleLine的位置
      circle.position.copy(endPoint);
      // 设置circleLine对象看向的位置
      circle.lookAt(startPoint);

      return { curve, curvePoints, circle };
    }

    function drawLine(pointVectors, scale = 1) {
      const inPoints = [];
      for (const pointVector of pointVectors) {
        // const point = pointVector.multiply(new THREE.Vector3(scale, scale, scale));
        // 将向量与所传入的标量scale进行相乘
        const point = pointVector.multiplyScalar(scale);
        inPoints.push(point);
      }
      // 三维样条曲线
      const curve = new THREE.CatmullRomCurve3(inPoints);
      const points = curve.getPoints(POINT_NUMBER);
      const line = makeLineByPoints(points);

      return line;
    }

    function makeLineByPoints(points) {
      const geometry = new THREE.BufferGeometry().setFromPoints(points);
      const material = new THREE.LineBasicMaterial({
        color: ColorEnum.black,
        linewidth: 2,
      });
      const line = new THREE.Line(geometry, material);
      return line;
    }

    return { cirLine, points, lastPoint };
  }
  drawCircularHelixNext(
    {
      position,
      newPoint,
      interval,
      radius,
      count,
      trimTurnsNum,
      type = DrawEnum.doubleHelixLine,
      nickname = DrawEnum.doubleHelixLine + "_" + this.doubleHelixLineCount,
    } = {},
    isInit
  ) {
    if (!newPoint.clone) {
      newPoint = new THREE.Vector3(newPoint.x, newPoint.y, newPoint.z);
    }

    if (!position.clone) {
      position = new THREE.Vector3(position.x, position.y, position.z);
    }

    const direction = new THREE.Vector3();
    direction.subVectors(newPoint, position);

    if (type === DrawEnum.doubleHelixLine) {
      const { cirLine, points, lastPoint } = this.drawCircularHelixDetail({
        position,
        direction,
        interval,
        radius,
        count,
        angle: 0,
        trimTurnsNum,
      });
      const {
        cirLine: cirLine2,
        points: points2,
        lastPoint: lastPoint2,
      } = this.drawCircularHelixDetail({
        position,
        direction,
        interval,
        radius,
        count,
        angle: Math.PI,
        trimTurnsNum,
      });

      const fullPoints = [...points, ...points2.reverse()];
      const fullLine = makeLineByPoints(fullPoints); // 结尾线是曲线
      fullLine.nickname = nickname;
      fullLine.name = nickname;
      fullLine.userData.nickname = nickname;
      this.nickname = fullLine.nickname;
      this.curvesMap[this.nickname] = {
        clickPoints: fullPoints,
      };
      fullLine.isTemporary = true;
      this.tempCurvesGroup.clear();
      this.tempCurvesGroup.add(fullLine);

      return {
        fullLine,
        fullPoints,
        position,
        newPoint,
        direction,
        interval,
        radius,
        count,
        trimTurnsNum,
        drawType: type,
        nickname,
      };
    } else if (type === DrawEnum.singleSpiralLine) {
      const { cirLine, points, lastPoint } = this.drawCircularHelixDetail({
        position,
        direction,
        interval,
        radius,
        count,
        angle: 0,
        trimTurnsNum,
      });
      const fullLine = makeLineByPoints(points);
      fullLine.nickname = nickname;
      fullLine.userData.nickname = nickname;
      this.nickname = fullLine.nickname;
      this.curvesMap[this.nickname] = {
        clickPoints: points,
      };
      fullLine.isTemporary = true;
      this.tempCurvesGroup.clear();
      this.tempCurvesGroup.add(fullLine);
      if (isInit) {
        fullLine.isTemporary = false;
        this.curvesGroup.add(fullLine);
        this.tempCurvesGroup.clear();
        raycasterObjs.push(fullLine);
      }
      return {
        fullLine,
        fullPoints: points,
        position,
        newPoint,
        direction,
        interval,
        radius,
        count,
        trimTurnsNum,
        drawType: type,
        nickname,
      };
    }

    function makeLineByPoints(points) {
      const geometry = new THREE.BufferGeometry().setFromPoints(points);
      const material = new THREE.LineBasicMaterial({
        color: ColorEnum.black,
        linewidth: 2,
      });
      const line = new THREE.Line(geometry, material);
      return line;
    }
  }
  /**
   * 按条件画螺旋线
   */
  drawCircularHelixByCondition(point, newPoint) {
    const distance = new THREE.Vector3(
      newPoint.x,
      newPoint.y,
      newPoint.z
    ).distanceTo(new THREE.Vector3(point.x, point.y, point.z));

    // 圈数
    const turnsNum = this.helixSetting.turnsNum;
    const trimTurnsNum = Math.floor(turnsNum);
    // 螺距
    const interval = distance / turnsNum;
    const radius = this.helixSetting.radius;
    const count = POINT_NUMBER;

    return this.drawCircularHelixNext({
      position: point,
      newPoint,
      interval,
      radius,
      count,
      trimTurnsNum,
      type: this.curDraw,
      nickname: this.nickname,
    });
  }
  /**
   * 绘制螺旋线
   */
  async drawCircularHelix(point, intersect) {
    if (!this.direction) {
      this.$modal.warning({ content: "请先选择视图模式" });
      return;
    }

    if (this.helixSetting.drawEnd) {
      return;
    }

    escCallback = () => {
      this.$message.destroy();
      this.stopDrawn();
      this.detachSelected();
      this.$emit("clearDraw");
      this.removeSceneObjByArray([this.helixSetting.point]);
      this.tempCurvesGroup.clear();
      if (this.curControl) {
        this.curControl.enabled = true;
      }
      this.inited = false;
      this.drawing = false; // 绘制结束
      if (this.getRenderer()?.domElement) {
        removeEventHandler(
          this.getRenderer().domElement,
          "pointermove",
          onMousemove
        );
      }
      // this.setPlaneMode();
      this.requestRender();
      this.helixSetting = {
        _point: null,
        drawEnd: false,
        showSetting: false,
        turnsNum: 2,
        radius: 10,
        point: null,
        newPoint: null,
        drawResult: null,
      };
      enterCallback = null;
      escCallback = null;
    };

    enterCallback = (event) => {
      this.$message.destroy();
      preventDefaults(event);
      this.stopDrawn();
      this.detachSelected();
      this.$emit("clearDraw");
      if (this.curControl) {
        this.curControl.enabled = true;
      }

      this.inited = false;
      this.drawing = false; // 绘制结束
      this.helixSetting.showSetting = false;
      if (commonfunc.getRenderer()?.domElement) {
        removeEventHandler(
          commonfunc.getRenderer().domElement,
          "pointermove",
          onMousemove
        );
      }

      if (this.helixSetting.drawResult) {
        this.drawCurve(this.nickname, this.helixSetting.drawResult.fullPoints);

        this.tempCurvesGroup.clear();
        commonfunc.removeSceneObjByArray([
          this.helixSetting.drawResult.fullLine,
          this.helixSetting.point,
        ]);
        // this.setPlaneMode();
        this.requestRender();
        this.isInitDrawCurve = false;
      }

      this.helixSetting = {
        _point: null,
        drawEnd: false,
        showSetting: false,
        turnsNum: 2,
        radius: 10,
        point: null,
        newPoint: null,
        drawResult: null,
      };

      this.detachSelected();
      escCallback = null;
      enterCallback = null;
    };

    const onMousemove = (event) => {
      if (this.helixSetting.drawEnd) {
        if (commonfunc.getRenderer()?.domElement) {
          removeEventHandler(
            commonfunc.getRenderer().domElement,
            "pointermove",
            onMousemove
          );
        }
        return;
      }
      const scene = commonfunc.getScene();
      for (const child of scene.children) {
        if (child && child.isTemporary && !child.isCenterPoint) {
          scene.remove(child);
        }
      }

      this.helixSetting.newPoint = null;
      this.helixSetting.drawResult = null;
      let intersects = this.getCanvasIntersects(
        event,
        scene,
        this.state.curCamera,
        commonfunc.getCanvas()
      );
      intersects = intersects.filter((i) => i.object.type === "GridHelper");
      if (intersects.length) {
        this.helixSetting.newPoint = this.getPoint(
          intersects[0].point
        ) as THREE.Vector3;
        if (this.helixSetting._point && this.helixSetting.newPoint) {
          this.helixSetting.drawResult = this.drawCircularHelixByCondition(
            this.helixSetting._point,
            this.helixSetting.newPoint
          );
        }
      }
    };

    if (this.helixSetting.point) {
      this.helixSetting.newPoint = this.getPoint(point) as THREE.Vector3;
      this.helixSetting.drawResult = this.drawCircularHelixByCondition(
        this.helixSetting._point,
        this.helixSetting.newPoint
      );
      this.helixSetting.drawEnd = true;
    } else {
      this.helixSetting._point = point;
      this.helixSetting.point = this.drawSphere(
        point,
        true,
        1,
        "center"
      ) as THREE.Mesh;
      this.helixSetting.newPoint = null;

      commonfunc
        .getRenderer()
        .domElement.addEventListener("pointermove", onMousemove, false);

      this.requestRender();

      this.helixSetting.showSetting = true;

      // this.$message.destroy();
      // this.$message.info('点击开始点和结束点，可以在右侧窗口修改圈数和半径，按【Enter回车】绘制完成，按【ESC】取消绘制', 0);
    }
  }
  resetMirror() {
    this.mirrorCurve.closeFunc && this.mirrorCurve.closeFunc();
    commonfunc.removeSceneObj([
      this.mirrorCurve.tempObj,
      this.mirrorCurve.mirrorItem,
    ]);
    this.mirrorCurve = {
      points: [],
      showMirrorSetting: false,
      closeFunc: null,
      curve: "",
      tempObj: null,
      mirrorItem: null,
    };
    escCallback = null;
  }
  getMirrorPlaneNormal(points) {
    const point = new THREE.Vector3();
    new THREE.Line3(...points).closestPointToPoint(camCenter, false, point);
    const vec = new THREE.Vector3();
    vec.subVectors.apply(null, ...points);
    const { x, y, z } = point;
    const diyNormal = this.gridHelper.diyNormal.clone().normalize();
    const nVector = diyNormal.cross(vec.normalize());
    const distance = -nVector.x * x - nVector.y * y - nVector.z * z;
    return { ...nVector, distance };
  }
  drawMirror(points, curveName) {
    const { clickPoints } = this.curvesMap[this.mirrorCurve.curve.nickname];
    const { x, y, z, distance } = this.getMirrorPlaneNormal(points);
    const mirrorMatrix = new THREE.Matrix4();
    mirrorMatrix.set(
      1 - 2 * x * x,
      -2 * x * y,
      -2 * x * z,
      -2 * x * distance,
      -2 * x * y,
      1 - 2 * y * y,
      -2 * y * z,
      -2 * y * distance,
      -2 * x * z,
      -2 * y * z,
      1 - 2 * z * z,
      -2 * z * distance,
      0,
      0,
      0,
      1
    );
    const newClickPoints = clickPoints.map((item) =>
      item.clone().applyMatrix4(mirrorMatrix)
    );

    this.curvesMap[curveName] = {
      spheres: [],
      clickPoints: newClickPoints,
    };
    const mesh = this.mirrorCurve.curve;
    const geometry = mesh.geometry.clone();
    geometry.applyMatrix4(mirrorMatrix);
    const newMesh = new Line2(geometry, mesh.material);
    commonfunc.getScene().add(newMesh);
    this.mirrorCurve.mirrorItem &&
      commonfunc.removeSceneObj(this.mirrorCurve.mirrorItem);
    this.mirrorCurve.mirrorItem = newMesh;
  }
  onDrawLineHandler(e) {
    let mirrorPoint;
    // this.$message.destroy();
    const curveType = this.getTypeByNickname(this.mirrorCurve.curve.nickname);
    const curveName = `${curveType}_${this[`${curveType}Count`] + 1}`;
    if (!this.mirrorCurve.tempObj) {
      this.mirrorCurve.tempObj = new THREE.Object3D();
      commonfunc.getScene().add(this.mirrorCurve.tempObj);
    }
    if (this.mirrorCurve.points.length < 2) {
      const mirrorPointVector = this.getCurrPoint(
        { clientX: e.clientX, clientY: e.clientY },
        (intersect) => {
          return intersect.object?.type === "GridHelper";
        }
      );
      if (!mirrorPointVector) return;
      mirrorPoint = this.drawSphere2(mirrorPointVector);
      this.mirrorCurve.points.push(mirrorPointVector);
      this.mirrorCurve.tempObj.add(mirrorPoint);
    }
    if (this.mirrorCurve.points.length === 1) {
      let line;
      this.rebackAdd(this.currentFunc, () => {
        this.mirrorCurve.closeFunc && this.mirrorCurve.closeFunc();
        commonfunc.removeSceneObj(this.mirrorCurve.tempObj);
        commonfunc.removeSceneObj(this.mirrorCurve.mirrorItem);
      });
      this.currentFunc = () => {
        // this.$message.destroy();
        // this.$message.info('请选择参考点', 0);
        this.mirrorCurve.closeFunc = this.addMousemoveEventListener(
          ({ clientX, clientY }) => {
            const pointerVector = this.getCurrPoint(
              { clientX, clientY },
              (intersect) => {
                return intersect.object?.type === "GridHelper";
              }
            );
            if (!pointerVector) return;
            const lineGeometry = new LineGeometry();
            const points = [...this.mirrorCurve.points, pointerVector];
            const bufferGeometry = new THREE.BufferGeometry().setFromPoints(
              points
            );
            lineGeometry.setPositions(
              bufferGeometry.attributes.position.array as number[]
            );
            const lineMaterial = getLineMaterial(
              ColorEnum.black,
              commonfunc.getCanvas(),
              2
            );
            if (line) this.mirrorCurve.tempObj?.remove(line);
            line = new Line2(lineGeometry, lineMaterial);
            this.mirrorCurve.tempObj?.add(line);
            this.drawMirror(points, curveName);
          }
        );
      };
      this.currentFunc();
    } else if (this.mirrorCurve.points.length === 2) {
      this.rebackAdd(
        this.currentFunc,
        ((mirrorPoint) => () => {
          this.mirrorCurve.tempObj.remove(mirrorPoint);
          this.mirrorCurve.points.length = 1;
          enterCallback = null;
        })(mirrorPoint)
      );
      this.mirrorCurve.closeFunc && this.mirrorCurve.closeFunc();
      this.mirrorCurve.closeFunc = null;
      enterCallback = () => {
        // this.curveCount++;
        this.controlling = false;
        this.$emit("closeActionControl");
        // this.$message.destroy();
        this.drawCurve(curveName, this.curvesMap[curveName].clickPoints);
        this.resetMirror();
        this.resetColorHandle();
        enterCallback = null;
        rebackList = [];
      };
    }
  }
  /**
   * 添加鼠标移动事件监听器
   * @param {Function} callback 事件监听回调函数
   * @param {Boolean} immediatelyClose 立即关闭
   * @param {Element|String} selector 监听节点对象
   * @return {Function} closeHandler 关闭监听函数
   */
  addMousemoveEventListener(
    callback = (event) => event,
    immediatelyClose = false,
    selector = null
  ) {
    let el;
    if (isEmpty(selector)) {
      el = document.querySelector("#mainCanvas");
    } else if (isString(selector) && selector !== null) {
      el = document.querySelector(selector);
    } else {
      el = selector;
    }

    const mousemoveHandler = (event) => {
      if (immediatelyClose) closeHandler();
      return callback(event);
    };
    el.addEventListener("mousemove", mousemoveHandler, false);

    const closeHandler = () => {
      el.removeEventListener("mousemove", mousemoveHandler);
    };

    return closeHandler;
  }
  onDrawPointHandler(e) {
    // this.$message.destroy();
    const curveType = this.getTypeByNickname(this.translate.curve.nickname);
    const curveName = `${curveType}_${this[`${curveType}Count`] + 1}`;
    if (!this.translate.tempObj) {
      this.translate.tempObj = new THREE.Object3D();
      commonfunc.getScene().add(this.translate.tempObj);
    }
    if (!this.translate.points.length) {
      this.rebackAdd(this.currentFunc, () => {
        // this.$message.destroy();
        this.modalEdit = false;
        this.translate.closeFunc && this.translate.closeFunc();
        this.translate.points = [];
        commonfunc.removeSceneObj(this.translate.currentItem);
      });
      this.currentFunc = ((ev) => () => {
        const pointVector = this.getCurrPoint(ev, (intersect) => {
          return intersect.object?.type === "GridHelper";
        });
        if (!pointVector) return;
        this.translate.points.push(pointVector);
        this.translate.closeFunc = this.addMousemoveEventListener(
          ({ clientX, clientY }) => {
            const pointVector = this.getCurrPoint(
              { clientX, clientY },
              (intersect) => {
                return intersect.object?.type === "GridHelper";
              }
            );
            if (!pointVector) return;
            this.translate.points = [this.translate.points[0], pointVector];
          }
        );
        // this.$message.info('请选择参考点', 0);
      })(e);
      this.currentFunc();
    } else if (this.translate.points.length === 2) {
      this.rebackAdd(this.currentFunc, () => {
        this.modalEdit = false;
        enterCallback = null;
      });
      this.modalEdit = true;
      this.translate.closeFunc && this.translate.closeFunc();
      this.translate.closeFunc = null;
      enterCallback = () => {
        this.controlling = false;
        this.$emit("closeActionControl");
        this.$message.destroy();
        // this.curveCount++;
        this.drawCurve(curveName, this.curvesMap[curveName].clickPoints);
        this.resetTranslate();
        this.resetColorHandle();
        this.translate.showSetting = false;
        enterCallback = null;
        rebackList = [];
      };
    }
  }

  resetTranslate() {
    this.translate.closeFunc && this.translate.closeFunc();
    commonfunc.removeSceneObj([
      this.translate.tempObj,
      this.translate.currentItem,
    ]);
    this.translate = {
      points: [],
      showSetting: false,
      closeFunc: undefined,
      curve: "",
      tempObj: undefined,
      currentItem: null,
    };
    escCallback = null;
  }
  /**
   * 颜色重置处理程序
   */
  resetColorHandle() {
    for (const raycasterObj of raycasterObjs) {
      if (!raycasterObj.material) {
        break;
      }
      if (this.isModelFace(raycasterObj)) {
        if (!raycasterObj.isLackFace) {
          // 非坏面(缺失的面)才可操作
          raycasterObj.material.color.set(new THREE.Color(this.originColor));
          raycasterObj.material.emissive.set(new THREE.Color(0x333333));
        }
      } else if (this.isLine(raycasterObj)) {
        raycasterObj.material.color.set(new THREE.Color(ColorEnum.black));
      }
      raycasterObj.material.needsUpdate = true;
    }
    this.requestRender();
  }
  onMouseClick(e) {
    // preventDefaults(e);
    // this.rightMenuVisible = false; // 关闭右键菜单
    this.removePointerEvent();

    if (this.props.taskInfoLoading) return;

    if (selectionBox) return;

    // 拾取选中拖动时，禁止单选操作
    // if (this.selectTarget) return;
    this.updatePointer(e);
    if (this.curPrePlaneMode) {
      this.onPrePlaneHandler(e);
    } else if (this.curDraw) {
      this.onDrawHandler(e);
    } else if (this.mirrorCurve.curve) {
      this.onDrawLineHandler(e);
    } else if (this.translate.curve) {
      this.onDrawPointHandler(e);
    } else if (this.canTransform) {
      let intersects = this.selectPartsHandle(e, true);
      // logger.log("onMouseClick intersects.length: ", intersects.length);
      if (this.chooseLine) return;
      intersects = intersects.filter(
        (item) =>
          (this.isYsLine(item.object, true) ||
            (this.isYsLine(item.object, false) && item.object.parent) ||
            this.isCircle(item.object)) &&
          !item.object.nickname?.startsWith("zyx")
      );
      if (!intersects.length) return;

      this.currentActiveItem = intersects[0].object;
      this.initTransFormControls(this.currentActiveItem);

      // if (!intersects.length) {
      // 	logger.log('初始化框选事件.');
      // 	this.initBoxSelectEvent();
      // } else {
      // 	logger.log('取消框选事件.');
      // 	this.removeBoxSelectListen();
      // }
    }
  }
  onMouseWheel(event) {
    debugger;
    if (this.state.curControl.zoomSpeed > 5) {
      return;
    }
    // this.scrolled = true;
    const deltaY = event.deltaY;
    const vector3Mesh = this.getIntersects(event.clientX, event.clientY)[0]
      ?.point;
    const { x, y } = this.getPosition(event);
    const vector = vector3Mesh || new THREE.Vector3(x, y, 1);
    this.initDistance();
    if (vector) {
      const AE = new THREE.Vector3().subVectors(
        vector,
        this.state.curCamera.position
      );
      const AB = AE.clone()
        .normalize()
        .multiplyScalar(-deltaY * 0.1);
      const OB = new THREE.Vector3().addVectors(
        this.state.curCamera.position,
        AB
      );
      const distance = OB.distanceTo(vector);
      const AC = new THREE.Vector3().subVectors(
        this.state.curControl.target,
        this.curCamera.position
      );
      const BE = new THREE.Vector3().subVectors(AE, AB);
      const BF = new THREE.Vector3().multiplyVectors(AC, BE).divide(AE);
      const OF = new THREE.Vector3()
        .addVectors(this.state.curCamera.position, AB)
        .add(BF);
      if (distance < -deltaY * 0.1) return;
      this.state.curCamera.position.add(AB);
      this.state.curControl.position0.add(AB);
      this.state.curControl.target = OF;
      this.state.curControl.update();
      const distance1 = this.state.curCamera.position.distanceTo(OF);
      this.updateRuler(false, this.state.distanceLong / distance1);
    }
  }
  initDistance = () => {
    if (this.state.distanceLong) return;
    const OA = this.state.curCamera.position;
    const OC = this.state.curControl.target;
    this.state.distanceLong = OA.distanceTo(OC);
  };
  /**
   * 获取点击对象
   */
  getIntersects(clientX, clientY) {
    return this.getCanvasIntersects(
      { clientX, clientY },
      commonfunc.getScene(),
      this.state.curCamera,
      commonfunc.getCanvas()
    );
  }

  /**
   * 当canvas不占满整屏时射线拾取存在偏差，获取点击对象
   * @param event 事件对象
   * @param scene 场景对象
   * @param camera 镜头对象
   * @param canvas 绘制盒子
   * @param isFilter 是否过滤掉隐藏的部件
   */
  getCanvasIntersects(event, scene, camera, canvas, isFilter = true) {
    preventDefaults(event);
    // 获取元素的大小及其相对于视口的位置
    const getBoundingClientRect = canvas.getBoundingClientRect();
    // 屏幕坐标转标准设备坐标
    const x =
      ((event.clientX - getBoundingClientRect.left) / canvas.offsetWidth) * 2 -
      1; // 标准设备横坐标
    const y =
      -((event.clientY - getBoundingClientRect.top) / canvas.offsetHeight) * 2 +
      1; // 标准设备纵坐标
    const vector = new THREE.Vector3(x, y, 0.5); // 标准设备坐标
    // 创建射线投射器对象
    const raycaster = new THREE.Raycaster();
    raycaster.params.Line = { threshold: 6 };
    // raycaster.params.Line2 = { threshold: 6 };
    raycaster.params.Points = { threshold: 6 };
    raycaster.setFromCamera(vector, camera);
    // 返回射线选中的对象 第二个参数如果不填 默认是false
    const objects = [...raycasterObjs];
    // if (this.gridHelper && this.curDraw !== DrawEnum.point) {
    //   objects.push(this.gridHelper);
    // }
    let intersects = raycaster.intersectObjects(objects, true);
    // 过滤掉隐藏的部件
    if (isFilter) {
      intersects = intersects.filter(
        (item) => item.object && item.object.visible
      );
    }
    // 返回选中的对象数组
    return intersects;
  }

  onMouseMove() {}
  initEvents = () => {
    debugger;
    const domElement = commonfunc.getRenderer()?.domElement;
    //   	  commonfunc.createControl
    this.setState({
      curControl: commonfunc.getCurrControl(),
    });
    addEventHandler(domElement, "click", this.onMouseClick, true);
    addEventHandler(domElement, "wheel", this.onMouseWheel, true);
    addEventHandler(domElement, "mousemove", this.onMouseMove, true);
    this.onMainCanvasResize();
    this.requestRender();
  };
  onMainCanvasResize() {
    const canvas = commonfunc.getCanvas();
    const renderer = commonfunc.getRenderer();
    const orthographicCamera = commonfunc.getOrthographicCamera();
    const perspectiveCamera = commonfunc.getPerspectiveCamera();
    const perspectiveControls = commonfunc.getPerspectiveControls();
    const orthographicControls = commonfunc.getOrthographicControls();

    const pixelRatio = window.devicePixelRatio;
    const width = (canvas.clientWidth * pixelRatio) | 0;
    const height = (canvas.clientHeight * pixelRatio) | 0;
    const needResize = canvas.width !== width || canvas.height !== height;
    const aspect = canvas.clientWidth / canvas.clientHeight;

    if (needResize) {
      renderer.setSize(width, height, false);
      const change = this.state.originalAspect / aspect;
      const newSize = viewSize * change;
      if (orthographicCamera) {
        orthographicCamera.left = (-aspect * newSize) / 2;
        orthographicCamera.right = (aspect * newSize) / 2;
        orthographicCamera.top = newSize / 2;
        orthographicCamera.bottom = -newSize / 2;
        orthographicCamera.updateProjectionMatrix();
      }

      if (perspectiveCamera) {
        perspectiveCamera.aspect = canvas.clientWidth / canvas.clientHeight;
        perspectiveCamera.updateProjectionMatrix();
      }

      if (perspectiveControls) {
        // perspectiveControls.handleResize();
      }
      if (orthographicControls) {
        // orthographicControls.handleResize();
      }
    }
    this.requestRender();
  }
  requestRender() {
    cancelAnimationFrame(animationId);
    animationId = requestAnimationFrame(this.render);
    // if (this.openAnimate) {
    //   this.render();
    // } else {
    //   cancelAnimationFrame(animationId);
    //   animationId = requestAnimationFrame(this.render);
    // }
  }
  initView = async () => {
    this.initScene();
    this.initRenderer();
    this.initLight();
    this.initCamera();
    initAxes(document.querySelector("#arrowCanvas"));
    this.initControls();
    this.initEvents();
    this.animate();
    this.updateRuler(true, 0);
  };
  updateRuler = (isInit = false, percent) => {
    if (isInit) {
      this.setState({
        rulerLoaded: true,
      });

      //父类调子类函数
      //@ts-ignore
      sleep(1, () => this.canvasRulerRef.updateRulerByReinit());
      return;
    }
    const zoom = percent || this.state.curCamera.zoom;
    let long = Number(toExponential(this.state.modelLong / zoom, 2));
    let lastZoom = zoom;
    //@ts-ignore
    sleep(1, () => this.canvasRulerRef.updateRulerByReinit(long));
    this.setState({
      rulerLoaded: true,
    });
  };
  initControls(controlType = commonfunc.ControlTypeEnum.Trackball) {
    commonfunc.setControlType(controlType);

    // if (this.getCameraType() === 'Perspective') {
    // 初始化透视相机控制器

    const perspectiveControls = commonfunc.createControl(
      commonfunc.getPerspectiveCamera(),
      camCenter
    );
    commonfunc.setPerspectiveControls(perspectiveControls);

    if (camCenter) {
      commonfunc.defaultData.camToSave.Perspective.controlCenter =
        camCenter.clone();
    }
    // } else {
    // 初始化正交相机控制器
    const orthographicControls = commonfunc.createControl(
      commonfunc.getOrthographicCamera(),
      camCenter
    );
    commonfunc.setOrthographicControls(orthographicControls);

    if (camCenter) {
      commonfunc.defaultData.camToSave.Orthographic.controlCenter =
        camCenter.clone();
    }
    // }
  }
  /**
   * 获取鼠标位置
   */
  getPosition = (event) => {
    const sliderWidth = 320;
    const headerHeight = 50;
    const navigationHeight = 0 + 2;
    const canvas = commonfunc.getCanvas();
    // 屏幕坐标转标准设备坐标
    const x =
      ((event.clientX - (this.state.collapsed ? 0 : sliderWidth)) /
        canvas.clientWidth) *
        2 -
      1; // 标准设备横坐标
    const y =
      -(
        (event.clientY - (headerHeight + navigationHeight)) /
        canvas.clientHeight
      ) *
        2 +
      1; // 标准设备纵坐标
    return { x, y };
  };
  initCamera = () => {
    const canvas = commonfunc.getCanvas();
    const aspectRatio = canvas.clientWidth / canvas.clientHeight;
    // this.state.originalAspect = aspectRatio;
    this.setState({
      originalAspect: aspectRatio,
    });
    let cameraType = "Orthographic";
    commonfunc.setCameraType(cameraType);
    const initCameraPosition = (camera) => {
      camera.position.set(0, 0, 200);
      camera.lookAt(camCenter);
      camera.updateMatrixWorld();
    };
    const perspectiveCamera = new THREE.PerspectiveCamera(
      50,
      aspectRatio,
      0.1,
      2000
    );
    initCameraPosition(perspectiveCamera);
    commonfunc.setPerspectiveCamera(perspectiveCamera);

    const orthographicCamera = new THREE.OrthographicCamera(
      (-aspectRatio * viewSize) / 2,
      (aspectRatio * viewSize) / 2,
      viewSize / 2,
      -viewSize / 2,
      0.1,
      2000
    );
    initCameraPosition(orthographicCamera);
    commonfunc.setOrthographicCamera(orthographicCamera);
    this.setState({
      curCamera: commonfunc.getCurrCamera(),
    });
  };
  initLight() {
    const scene = commonfunc.getScene();

    // 从顶部和底部发出不同颜色的光，模拟来自“地面”和“天空”的反射光
    scene.add(new THREE.HemisphereLight(0xc7e8ff, 0xffe3b3, 0.4));

    const light1 = new THREE.DirectionalLight(ColorEnum.white, 0.4);
    light1.position.set(5, -2, 3);
    scene.add(light1);

    const light2 = new THREE.DirectionalLight(ColorEnum.white, 0.4);
    light2.position.set(-5, 2, 3);
    scene.add(light2);
  }
  initScene() {
    const scene = new THREE.Scene();
    const canvas = document.querySelector("#mainCanvas");
    commonfunc.setScene(scene);
    commonfunc.setCanvas(canvas as HTMLCanvasElement);
  }

  loadDataV3 = async (result) => {
    // this.openLoading();
    let meshes: never[] = [];
    let faces: never[] = [];
    if (result["meshes"]) {
      meshes = await this.loadRhinoFacesJson("meshes", result);
      if (meshes?.length) {
        raycasterObjs.push(...meshes);
      }
    }
    if (result["faces"]) {
      faces = await this.loadRhinoFacesJson("faces", result);
      if (faces?.length) {
        raycasterObjs.push(...faces);
      }
    }
  };
  initRenderer() {
    const renderer = new THREE.WebGLRenderer({
      alpha: true,
      antialias: true,
      canvas: commonfunc.getCanvas(),
      // sortObjects: true,
    });
    // Clear bg so we can set it with css
    renderer.setClearColor(ColorEnum.black, 0);
    commonfunc.setRenderer(renderer);
  }
  animate = () => {
    cancelAnimationFrame(animationId);
    animationId = requestAnimationFrame(this.animate);
    this.renderView();
    console.log("render");
  };
  renderView = () => {
    // this.renderRequested = false;

    const scene = commonfunc.getScene();
    const renderer = commonfunc.getRenderer();
    const cameraType = commonfunc.getCameraType();
    const arrowScene = commonfunc.getArrowScene();
    const arrowCamera = commonfunc.getArrowCamera();
    const arrowRenderer = commonfunc.getArrowRenderer();
    const perspectiveCamera = commonfunc.getPerspectiveCamera();
    const orthographicCamera = commonfunc.getOrthographicCamera();
    const perspectiveControls = commonfunc.getPerspectiveControls();
    const orthographicControls = commonfunc.getOrthographicControls();

    perspectiveControls?.update();
    orthographicControls?.update();

    if (arrowCamera) {
      if (cameraType === "Perspective" && perspectiveControls) {
        arrowCamera.position.copy(perspectiveCamera.position);
        arrowCamera.position.sub(perspectiveControls.target);
      }
      if (cameraType === "Orthographic" && orthographicControls) {
        arrowCamera.position.copy(orthographicCamera.position);
        arrowCamera.position.sub(orthographicControls.target);
      }
      arrowCamera.lookAt(arrowScene.position);
      arrowCamera.position.setLength(200);
    }

    // this.stats?.begin();
    if (cameraType === "Perspective" && perspectiveControls) {
      renderer?.render(scene, perspectiveCamera);
    }
    if (cameraType === "Orthographic" && orthographicControls) {
      renderer?.render(scene, orthographicCamera);
    }
    arrowRenderer?.render(arrowScene, arrowCamera);
    // this.stats?.end();
  };
  render() {
    return (
      <div className="view-container">
        <div className="js-view">
          <canvas id="mainCanvas"></canvas>
          <canvas id="arrowCanvas"></canvas>
          <div id="label"></div>
          <CanvasRulerContainer
            long={200}
            clientWidth={300}
            ref={"canvasRulerRef"}
            onRef={(c) => (this.canvasRulerRef = c)}
            // ref={this.canvasRulerRef}
            refer={this.canvasRulerRef}
          />
        </div>
      </div>
    );
  }
}
export default ShoeView;
